import { ConfigService } from '@nestjs/config'
import moment from 'moment'
import nanoid from 'nanoid'
import { Server } from 'socket.io'
import { roomConfig } from '../../config/room'
import { User } from '../../models/User'
import { AppError } from '../../utils/AppError'
import { RedisService } from '../redis/RedisService'
import { RoomStateService } from './RoomStateService'

export class RoomService {
  private io: Server
  private redis: RedisService
  private roomState: RoomStateService

  constructor(io: Server, private readonly configService: ConfigService) {
    this.io = io
    this.redis = new RedisService(configService)
    this.roomState = new RoomStateService(this.redis)
  }

  // 创建房间
  async createRoom(data: {
    userId: string
    title: string
    cover?: string
    category?: string
    tags?: string[]
    notice?: string
    password?: string
  }) {
    const { userId, title, cover, category, tags, notice, password } = data

    // 检查用户权限
    const user = await User.findById(userId)
    if (!user || user.level < this.configService.get('room.createRoom.minLevel')) {
      throw new AppError(403, '您的等级不足以创建房间')
    }

    // 检查用户是否已有房间
    const existingRoom = await this.redis.hget(`user:${userId}:info`, 'roomId')
    if (existingRoom) {
      throw new AppError(400, '您已经拥有一个房间')
    }

    // 生成房间ID
    const roomId = nanoid.nanoid(10)

    // 创建房间信息
    const room = {
      id: roomId,
      owner: userId,
      title: title.trim(),
      cover: cover || roomConfig.defaultCover,
      category: category || '其他',
      tags: tags || [],
      notice: notice || '',
      password: password || '',
      status: 'offline',
      createTime: Date.now(),
      lastLiveTime: 0,
      totalLiveTime: 0,
      currentViewers: 0,
      totalViewers: 0,
      followers: 0,
      blockedUsers: [],
    }

    // 保存房间信息
    await this.redis.hmset(`room:${roomId}:info`, room)

    // 更新用户信息
    await this.redis.hset(`user:${userId}:info`, 'roomId', roomId)

    // 创建房间统计信息
    await this.redis.hmset(`room:${roomId}:stats`, {
      danmaku: 0,
      gift: 0,
      income: 0,
      maxOnline: 0,
    })

    return room
  }

  // 获取房间信息
  async getRoomInfo(roomId: string) {
    const room = await this.redis.hgetall(`room:${roomId}:info`)
    if (!room || !room.id) {
      throw new AppError(404, '房间不存在')
    }

    // 获取房主信息
    const owner = await User.findById(room.owner).select('nickname avatar level badges vipLevel')

    // 获取房间统计信息
    const stats = await this.redis.hgetall(`room:${roomId}:stats`)

    return {
      ...room,
      owner: {
        id: owner.id,
        nickname: owner.nickname,
        avatar: owner.avatar,
        level: owner.level,
        badge: owner.badges[0],
        vipLevel: owner.vipLevel,
      },
      stats,
    }
  }

  // 更新房间信息
  async updateRoom(roomId: string, userId: string, data: any) {
    // 验证房间所有权
    const owner = await this.redis.hget(`room:${roomId}:info`, 'owner')
    if (owner !== userId) {
      throw new AppError(403, '您不是该房间的主播')
    }

    // 更新房间信息
    const updates = {}
    const allowedFields = ['title', 'cover', 'category', 'tags', 'notice', 'password']

    for (const field of allowedFields) {
      if (data[field] !== undefined) {
        updates[field] = data[field]
      }
    }

    if (Object.keys(updates).length > 0) {
      await this.redis.hmset(`room:${roomId}:info`, updates)
    }

    return await this.getRoomInfo(roomId)
  }

  // 开始直播
  async startLive(roomId: string) {
    const room = await this.redis.hgetall(`room:${roomId}:info`)
    if (!room || room.status === 'live') {
      throw new AppError(400, '房间状态异常')
    }

    // 更新房间状态
    await this.redis.hmset(`room:${roomId}:info`, {
      status: 'live',
      lastLiveTime: Date.now(),
    })

    // 广播开播通知
    this.io.emit('live_start', {
      roomId,
      startTime: Date.now(),
    })

    // 更新直播分类排行
    await this.redis.zadd(`category:${room.category}:live`, Date.now(), roomId)
  }

  // 结束直播
  async endLive(roomId: string) {
    const room = await this.redis.hgetall(`room:${roomId}:info`)
    if (!room || room.status !== 'live') {
      throw new AppError(400, '房间状态异常')
    }

    // 计算直播时长
    const liveTime = Date.now() - parseInt(room.lastLiveTime)
    const totalLiveTime = parseInt(room.totalLiveTime) + liveTime

    // 更新房间状态
    await this.redis.hmset(`room:${roomId}:info`, {
      status: 'offline',
      totalLiveTime,
    })

    // 广播下播通知
    this.io.emit('live_end', {
      roomId,
      endTime: Date.now(),
      duration: liveTime,
    })

    // 从直播分类中移除
    await this.redis.zrem(`category:${room.category}:live`, roomId)

    // 记录直播历史
    await this.saveLiveHistory(roomId, {
      startTime: parseInt(room.lastLiveTime),
      endTime: Date.now(),
      duration: liveTime,
      maxViewers: await this.redis.hget(`room:${roomId}:stats`, 'maxOnline'),
      totalIncome: await this.redis.hget(`room:${roomId}:stats`, 'income'),
    })
  }

  // 获取直播列表
  async getLiveRooms(options: {
    category?: string
    page?: number
    pageSize?: number
    sort?: 'hot' | 'new'
  }) {
    const { category, page = 1, pageSize = 20, sort = 'hot' } = options

    let rooms
    if (category) {
      // 获取分类直播
      rooms = await this.redis.zrevrange(
        `category:${category}:live`,
        (page - 1) * pageSize,
        page * pageSize - 1
      )
    } else {
      // 获取所有直播
      const keys = await this.redis.keys('room:*:info')
      rooms = await Promise.all(keys.map((key) => this.redis.hgetall(key)))
      rooms = rooms.filter((room) => room.status === 'live')
    }

    // 获取房间详细信息
    const roomInfos = await Promise.all(rooms.map((room) => this.getRoomInfo(room.id)))

    // 排序
    if (sort === 'hot') {
      roomInfos.sort((a, b) => b.currentViewers - a.currentViewers)
    } else {
      roomInfos.sort((a, b) => b.lastLiveTime - a.lastLiveTime)
    }

    return roomInfos
  }

  // 保存直播历史
  private async saveLiveHistory(roomId: string, data: any) {
    const key = `room:${roomId}:live_history`
    await this.redis.lpush(
      key,
      JSON.stringify({
        ...data,
        date: moment().format('YYYY-MM-DD'),
      })
    )
    await this.redis.ltrim(key, 0, this.configService.get('room.history.maxLength') - 1)
  }
}
